#!/bin/bash
# * =====================================================
# * Copyright © hk. 2022-2025. All rights reserved.
# * File name  : build.sh
# * Author     : 苏木
# * Date       : 2025-05-22
# * ======================================================
##

# 脚本和工程路径
# ========================================================
SCRIPT_NAME=${0#*/}
SCRIPT_CURRENT_PATH=${0%/*}
SCRIPT_ABSOLUTE_PATH=`cd $(dirname ${0}); pwd`
PROJECT_ROOT=${SCRIPT_ABSOLUTE_PATH} # 工程的源码目录，一定要和编译脚本是同一个目录
SOFTWARE_DIR_PATH=~/2software        # 软件安装目录
TFTP_DIR=~/3tftp
NFS_DIR=~/4nfs
CPUS=$(($(nproc)-1))                 # 使用总核心数-1来多线程编译

# 打开错误状态监测
# ========================================================
# -e 表示当脚本中的任何命令以 ‌非零状态（失败）‌ 退出时，立即终止脚本执行
# -E 确保 ERR 陷阱（trap）在 ‌函数、子 Shell 或命令替换‌ 中生效
set -eE

# 可用的emoji符号
# ========================================================
# https://www.w3school.com.cn/charsets/ref_emoji.asp
function usage_emoji()
{
    echo -e "⚠️ ✅ ❌ 🚩 📁 🕣️ 🔔"
}

# 颜色和日志标识
# ========================================================
# |      ---       |Black |  Red | Green | Yellow | Blue | Magenta | Cyan | White |
# | Fore(Standard) |  30  |  31  |  32   |   33   |  34  |   35    |  35  |   37  |
# | Fore(light)    |  90  |  91  |  92   |   93   |  94  |   95    |  95  |   97  |
# | Back(Standard) |  40  |  41  |  42   |   43   |  44  |   45    |  46  |   47  |
# | Back(light)    | 100  | 101  | 102   |  103   | 104  |  105    | 106  |  107  |
BLACK="\033[1;30m"
RED='\033[1;31m'    # 红
GREEN='\033[1;32m'  # 绿
YELLOW='\033[1;33m' # 黄
BLUE='\033[1;34m'   # 蓝
PINK='\033[1;35m'   # 紫
CYAN='\033[1;36m'   # 青
WHITE='\033[1;37m'  # 白
CLS='\033[0m'       # 清除颜色

INFO="${GREEN}INFO: ${CLS}"
WARN="${YELLOW}WARN: ${CLS}"
ERROR="${RED}ERROR: ${CLS}"

# 日志打印
# ========================================================
# Export global functions
set -a # 自动导出，相当于export

function sh_log()
{
	LOG_COLOR="$1"           # 获取要显示的前景色
	shift                    # 参数左移
	if [ "$1" = "-n" ]; then # -n表示取消echo的换行
		shift
		LOG_FLAG="-ne"
	else
		LOG_FLAG="-e"
	fi
	echo $LOG_FLAG "\e[${LOG_COLOR}m$@\e[0m"

}

function prt()
{
	sh_log 0 "$@" # default
}

function message()
{
	sh_log 36 "$@" # light blue
}

function notice()
{
    echo -n "✨ "
	sh_log 35 "$@" # purple
}

function warning()
{
    echo -n "⚠️  "
	sh_log 33 "$@" # dark yellow
}

function error()
{
    echo -n "🔖 "
	sh_log 91 "$@" # light red
}

function success()
{
    echo -n "✅ "
	sh_log 32 "$@" # light red
}

function fatal()
{
    echo -n "🔖 "
	sh_log 31 "$@" # dark red
}

function info()
{
    echo -ne "${INFO}"
	sh_log 0 "$@" # dark red
}

function log_echo_demo()
{
    info "log help:"
    prt -n "Log colors:|"
	message -n " message |"
    success -n " success |"
	notice -n " notice |"
	warning -n " warning |"
	error -n " error |"
	fatal " fatal |"
	echo
}
set +a
# End of global functions

# 调试信息
# ========================================================
HOOK_RET=0             # 存储命令的状态
trap 'err_handler' ERR # trap 是用于信号处理的内置命令，可捕获系统信号或脚本事件并执行指定操作，常用于实现资源清理、中断处理和调试功能
                       #  EXIT	0	脚本正常退出时触发
                       #  ERR	-	命令返回非零状态码时触发，但是若命令返回值被捕获的话就不会触发
                       #            例如 false || exit_code=1
function err_handler()
{
	ret=${1:-$?}
	if [ "$ret" -eq 0 ]; then
		return 0
	fi

	fatal "ERROR: Running $BASH_SOURCE - ${2:-${FUNCNAME[1]}} failed!"
	fatal "ERROR: exit code $ret from line ${BASH_LINENO[0]}:"
	fatal "    ${3:-$BASH_COMMAND}"
	fatal "ERROR: call stack:"
	for i in $(seq 1 $((${#FUNCNAME[@]} - 1))); do
		SOURCE="${BASH_SOURCE[$i]}"
		LINE=${BASH_LINENO[$(( $i - 1 ))]}
		fatal "    $(basename "$SOURCE"): ${FUNCNAME[$i]}($LINE)"
	done
	exit $ret
}

function err_handler_demo()
{
    false                  # 这种写法会直接触发trap注册的处理函数
    # HOOK_RET=${PIPESTATUS[0]}
	# if [ $HOOK_RET -ne 0 ]; then
	# 	err_handler $HOOK_RET "${FUNCNAME[0]} $*" "$@"
	# 	exit $HOOK_RET
	# fi
}

function err_handler_demo_test()
{
    err_handler_demo err_test_demo 1
}

# 时间计算
# ========================================================
TIME_START=
TIME_END=

function get_start_time()
{
	TIME_START=$(date +'%Y-%m-%d %H:%M:%S')
}

function get_end_time()
{
	TIME_END=$(date +'%Y-%m-%d %H:%M:%S')
}

function get_execute_time()
{
	start_seconds=$(date --date="$TIME_START" +%s);
	end_seconds=$(date --date="$TIME_END" +%s);
	duration=`echo $(($(date +%s -d "${TIME_END}") - $(date +%s -d "${TIME_START}"))) | awk '{t=split("60 s 60 m 24 h 999 d",a);for(n=1;n<t;n+=2){if($1==0)break;s=$1%a[n]a[n+1]s;$1=int($1/a[n])}print s}'`
	echo "===*** 🕣️ 运行时间：$((end_seconds-start_seconds))s,time diff: ${duration} ***==="
}

function time_count_down
{
    for i in {3..0}
    do     

        echo -ne "${INFO}after ${i} is end!!!"
        echo -ne "\r\r"        # echo -e 处理特殊字符  \r 光标移至行首，但不换行
        sleep 1
    done
    echo "" # 打印一个空行，防止出现混乱
}

function get_run_time_demo()
{
    get_start_time
    time_count_down
    get_end_time
    get_execute_time
}

# 目录切换函数定义
# ========================================================
function cdi()
{
    if command -v pushd &>/dev/null; then
        # 压栈并切换
        pushd $1 >/dev/null || return 1
    else
        cd $1
    fi
}

function cdo()
{
    if command -v popd &>/dev/null; then
        # 弹出并恢复
        popd >/dev/null || return 1
    else
        cd -
    fi
}

# 命令执行函数定义
# ========================================================
#execute执行语句成功与否打印,此命令不会触发,主要是用于一些需要sudo的命令，这里可以自动判断
function execute() 
{
    local PASSWD="000000"
    local execute_exit_code=0
    local cmd_str

    # local cmd_str_src
    # printf -v cmd_str_src "%q " "$@" # 构造安全的命令字符串,不转义特殊字符

    # 重组所有参数为命令字符串（保留用户输入的转义符号）
    cmd_str=$(printf "%s " "$@" | sed 's/ $//')
    cmd_str=${cmd_str% }  # 移除末尾空格

    # 打印命令（高亮提示）
    if [ "$EUID" -ne 0 ]; then
        printf "\033[36mcmd:\033[0m sudo %s\n" "$cmd_str"
    else
        printf "\033[36mcmd:\033[0m %s\n" "$cmd_str"
    fi

    # 执行命令（通过 bash -c 解析复杂命令）
    if [ "$EUID" -ne 0 ]; then
        echo "$PASSWD" | sudo -S bash -c "$cmd_str" || execute_exit_code=1
    else
        bash -c "$cmd_str" || execute_exit_code=1
    fi

    # 错误处理
    if [ $execute_exit_code -ne 0 ]; then
        error "执行 $cmd_str 失败!"
        return 1 # trap 仅对当前 Shell 进程有效，子进程继承独立的信号处理环境，父进程无法感知子进程的 exit 行为
                 # 这里用return可以保持进程统一性，确保 trap 生效
    fi
}

function execute_demo()
{
    
    # execute false # 用于测试出错后被tap捕获
    execute apt-get update # 加上soudo执行

    local str=sumu1
    execute echo "${str}" \> /etc/demo.txt
    info "demo.txt内容如下:"
    cat /etc/demo.txt
    echo

    str=sumu2
    execute echo "${str}" \| tee -a /etc/demo.txt
    info "demo.txt内容如下:"
    cat /etc/demo.txt
    echo

    str=sumu3
    execute echo "${str}" \>\> /etc/demo.txt
    info "demo.txt内容如下:"
    cat /etc/demo.txt
    echo
}

# 开发环境信息
# ========================================================
function get_ubuntu_info()
{
    local kernel_version=$(uname -r) # 获取内核版本信息，-a选项会获得更详细的版本信息
    local ubuntu_version=$(lsb_release -ds) # 获取Ubuntu版本信息

    
    local ubuntu_ram_total=$(cat /proc/meminfo |grep 'MemTotal' |awk -F : '{print $2}' |sed 's/^[ \t]*//g')   # 获取Ubuntu RAM大小
    local ubuntu_swap_total=$(cat /proc/meminfo |grep 'SwapTotal' |awk -F : '{print $2}' |sed 's/^[ \t]*//g') # 获取Ubuntu 交换空间swap大小
    #local ubuntu_disk=$(sudo fdisk -l |grep 'Disk' |awk -F , '{print $1}' | sed 's/Disk identifier.*//g' | sed '/^$/d') #显示硬盘，以及大小
    local ubuntu_cpu=$(grep 'model name' /proc/cpuinfo |uniq |awk -F : '{print $2}' |sed 's/^[ \t]*//g' |sed 's/ \+/ /g') #cpu型号
    local ubuntu_physical_id=$(grep 'physical id' /proc/cpuinfo |sort |uniq |wc -l) #物理cpu个数
    local ubuntu_cpu_cores=$(grep 'cpu cores' /proc/cpuinfo |uniq |awk -F : '{print $2}' |sed 's/^[ \t]*//g') #物理cpu内核数
    local ubuntu_processor=$(grep 'processor' /proc/cpuinfo |sort |uniq |wc -l) #逻辑cpu个数(线程数)
    local ubuntu_cpu_mode=$(getconf LONG_BIT) #查看CPU当前运行模式是64位还是32位

    # 打印结果
    prt "ubuntu: $ubuntu_version - $ubuntu_cpu_mode"
    prt "kernel: $kernel_version"
    prt "ram   : $ubuntu_ram_total"
    prt "swap  : $ubuntu_swap_total"
    prt "cpu   : $ubuntu_cpu,physical id is$ubuntu_physical_id,cores is $ubuntu_cpu_cores,processor is $ubuntu_processor"
}

# 本地虚拟机VMware开发环境信息
function get_dev_env_info()
{
    prt "Development environment: "
    prt "ubuntu : 20.04.2-64(1核12线程 16GB RAM,512GB SSD) arm"
    prt "VMware : VMware® Workstation 17 Pro 17.6.0 build-24238078"
    prt "Windows: "
    prt "          处理器 AMD Ryzen 7 5800H with Radeon Graphics 3.20 GHz 8核16线程"
    prt "          RAM	32.0 GB (31.9 GB 可用)"
    prt "          系统类型	64 位操作系统, 基于 x64 的处理器"
    prt "linux开发板原始系统组件版本:"
    prt "          uboot : v2019.04 https://github.com/nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0"
    prt "          kernel: v4.19.71 https://github.com/nxp-imx/linux-imx/releases/tag/v4.19.71"
    prt "          rootfs: buildroot-2023.05.1 https://buildroot.org/downloads/buildroot-2023.05.1.tar.gz"
    prt ""
    prt "x86_64-linux-gnu   : gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.2)"
    prt "arm-linux-gnueabihf:"
    prt "          arm-linux-gnueabihf-gcc 8.3.0"
    prt "          https://developer.arm.com/-/media/Files/downloads/gnu-a/8.3-2019.03/binrel/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf.tar.xz"
}

# 环境变量
# ========================================================
# Github Actions托管的linux服务器有以下用户级环境变量，系统级环境变量加上sudo好像也权限修改
# .bash_logout  当用户注销时，此文件将被读取，通常用于清理工作，如删除临时文件。
# .bashrc       此文件包含特定于 Bash Shell 的配置，如别名和函数。它在每次启动非登录 Shell 时被读取。
# .profile、.bash_profile 这两个文件位于用户的主目录下，用于设置特定用户的环境变量和启动程序。当用户登录时，
#                        根据 Shell 的类型和配置，这些文件中的一个或多个将被读取。
USER_ENV=(~/.bashrc ~/.profile ~/.bash_profile)
SYSENV=(/etc/profile) # 系统环境变量位置
ENV_FILE=("${USER_ENV[@]}" "${SYSENV[@]}")

function source_env_info()
{
    for temp in ${ENV_FILE[@]};
    do
        if [ -f ${temp} ]; then
            prt "${INFO}source ${temp}"
            source ${temp}
        fi
    done
}


# ========================================================
# 功能实现
# ========================================================
EXECUTE_MODE=manu
BUILD_MODE=build
MAKE_PARAM[0]="--no-print-directory"
MAKE_PARAM[1]="V=0"

CMAKE_PARAM[0]=""
function usage()
{
	prt "================================================="
    prt "${PINK}Usage: ./${SCRIPT_NAME} [options]${CLS}"
    prt "Options:"
    prt "${PINK}-h, --help       : 显示帮助信息${CLS}"
    prt "${PINK}-a               : 自动执行所有步骤${CLS}"
    prt "${PINK}-b               : 构建工程 (需配合-a,这是默认的)${CLS}"
    prt "${PINK}-c               : 清理工程 (需配合-a)${CLS}"
    prt "${PINK}-i               : 安装成果物 (需配合-a)${CLS}"
    prt "${PINK}-u               : 卸载成果物 (需配合-a)${CLS}"
    prt "${PINK}-v 1             : 详细输出模式${CLS}"
    prt "${PINK}-l               : 显示日志颜色示例${CLS}"
    prt "${PINK}-p 1             : 示例参数选项${CLS}"
    prt "================================================="
    prt "${PINK}示例:${CLS}"
    prt "${PINK}./${SCRIPT_NAME} -h      显示帮助${CLS}"
    prt "${PINK}./${SCRIPT_NAME} -a      自动构建项目${CLS}"
    prt "${PINK}./${SCRIPT_NAME} -a -b   自动构建项目${CLS}"
    prt "${PINK}./${SCRIPT_NAME} -a -c   清理项目${CLS}"
    prt "${PINK}./${SCRIPT_NAME} -a -i   安装成果物${CLS}"
    prt "${PINK}./${SCRIPT_NAME} -a -u   卸载成果物${CLS}"
    prt "================================================="
}
# 脚本运行参数处理
notice "There are $# parameters: $@ (\$1~\$$#)"
while getopts "abchipuv:" arg #选项后面的冒号表示该选项需要参数
    do
        case ${arg} in
            a) EXECUTE_MODE="auto" ;;
			b) BUILD_MODE="build" ;;
			c) BUILD_MODE="clean" ;;
            l) log_echo_demo ;;
			h) 
				usage
				exit 0
				;;
			i) BUILD_MODE="install" ;;
            p)
                if [ $OPTARG == "1" ];then
                    message "OPTARG=$OPTARG"
                fi
                ;;
			u) BUILD_MODE="uninstall" ;;
            v)
                if [ $OPTARG == "1" ];then
                    MAKE_PARAM[0]=""
                    MAKE_PARAM[1]="V=1"
					CMAKE_PARAM[0]="VERBOSE=1"
                fi
                ;;
            ?)  #当有不认识的选项的时候arg为?
                error "unkonw argument..."
                exit 1
                ;;
        esac
    done

# 功能函数实现
# ========================================================
CMAKE_INSTALL_PATH=${PROJECT_ROOT}/../install
CMAKE= # cmake的版本

function cmake_check()
{
    # 严格按顺序检测的路径列表（优先级从高到低）
    local check_paths=(
        "${HOME}/tools/cmake-3.16.3-Linux-x86_64/bin/cmake"      # 优先级1
		"${HOME}/tools/cmake-4.0.2-linux-x86_64/bin/cmake"       # 优先级2
        "${HOME}/2software/cmake-3.16.3-Linux-x86_64/bin/cmake"  # 优先级3
        "${HOME}/2software/cmake-4.0.2-linux-x86_64/bin/cmake"   # 优先级4
        "/usr/bin/cmake"                                         # 优先级5（系统默认）
    )
    local selected_cmake=""

    # 遍历路径列表，找到第一个存在的可执行文件
    for path in "${check_paths[@]}"; do
        if [[ -x "${path}" ]]; then
            selected_cmake="${path}"
            break  # 找到后立即停止搜索
        fi
    done

    # 结果处理
    if [[ -n "${selected_cmake}" ]]; then
        # 提取并显示版本号
		CMAKE=${selected_cmake}
        local version=$($CMAKE --version | head -n1) #$("${selected_cmake}" --version | awk '/cmake version/ {print $3}')
        info "选择 ${version}, 路径为 ${selected_cmake}"
    else
		error "找不到任何可用的CMake~" >&2
        error "请安装CMake到以下位置之一:" >&2
        error "1. 自定义路径: ${HOME}/2software" >&2
        error "2. 系统路径: /usr/bin" >&2
        return 1
    fi

	# if command -v cmake &> /dev/null; then # CMAKE_PATH为空时可以使用系统默认的cmake
	# 	version_info=$("$cmake_executable" --version | head -n1)
	# 	info "CMake 存在: $(which cmake), 版本为：$(cmake --version | head -n1)"
	# 	return 0
	# else
	# 	error "系统不存在cmake, 请安装cmake工具!"
	# 	return 1
	# fi
}

function cmake_build_all()
{
	cdi ${PROJECT_ROOT}
    prt "${PINK}cur_path :$(pwd)${CLS}"
	cmake_check || { 
		return 1 
	}
    # 创建构建目录
	if [ ! -d "build" ];then
		mkdir -p build
	fi 
	cdi build
	# 生成构建系统
	${CMAKE} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PATH} ..
	# 编译工程
	${CMAKE} --build . -- -j${CPUS} ${CMAKE_PARAM[@]}
	cdo
	prt "${PINK}cur_path :$(pwd)${CLS}"
	if [ -f "build/compile_commands.json" ];then
		ln -svf build/compile_commands.json .
	fi
	success "工程构建完毕!"
	cdo
}

function cmake_clean_all()
{
	cdi ${PROJECT_ROOT}
    prt "${PINK}cur_path :$(pwd)${CLS}"
	if [ -d "build" ];then
    	rm -rf build
	fi
	success "build目录清理完成!"
	cdo
}

function cmake_install()
{
	cdi ${PROJECT_ROOT}
    prt "${PINK}cur_path :$(pwd)${CLS}"
	cmake_check || { 
		return 1 
	}
    # 创建构建目录
	if [ ! -d "build" ];then
		warning "build 目录不存在!"
		return 0
	fi 

	cdi build
	info "将安装到 ${CMAKE_INSTALL_PATH}(default path: /usr/local)..."
	# 确保安装目录存在
	if [ ! -d "${CMAKE_INSTALL_PATH}" ]; then
		mkdir -p "${CMAKE_INSTALL_PATH}" || {
			error "无法创建安装目录: ${CMAKE_INSTALL_PATH}"
			return 1
		}
		success "已创建安装目录: ${CMAKE_INSTALL_PATH}"
	fi
	# make install
	${CMAKE} --build . --target install
	cdo

	if command -v tree &> /dev/null; then
		cdi ${CMAKE_INSTALL_PATH}
		tree . -L 5
		cdo
	fi
	
	success "成果物安装完毕, 已安装到 ${CMAKE_INSTALL_PATH}!"
	cdo
}

function cmake_rm_empty_dirs() 
{
    # 用法: rm_empty_dirs [目录路径] 
    # 功能: 递归删除指定目录下的所有空目录，自动跳过.git目录
    # 参数: 目录路径 (可选，默认为当前目录)
    
    local target_dir="${1:-.}"
    local exclude_dirs=(".git")  # 可在此扩展其他排除目录
	local deleted_dirs=0
	local empty_dirs=()
	
    # 参数检查
    if [ $# -gt 1 ]; then
        info "Usage: ${FUNCNAME[0]} [directory]" >&2
        return 0
    fi

    if [ ! -d "$target_dir" ]; then
        error "错误：目录不存在 '$target_dir'" >&2
        return 0
    fi

    # 构建排除条件表达式
    local exclude_conditions=()
    for dir in "${exclude_dirs[@]}"; do
        exclude_conditions+=(-not -path "*/$dir" -not -path "*/$dir/*")
    done

    # 执行删除操作
    info "正在扫描目录：$target_dir"
	while IFS= read -r -d $'\0' dir; do
        # 尝试删除目录，成功时计数
        if rmdir "$dir" 2>/dev/null; then
            # echo "已删除空目录: $dir"
			empty_dirs+=($dir)
            deleted_dirs=$((deleted_dirs + 1))  # 兼容性更强的写法
        fi
    done < <(find "$target_dir" -depth -type d \( "${exclude_conditions[@]}" \) -print0)

    # 结果输出
    if [ "$deleted_dirs" -eq 0 ]; then
        warning "未找到可删除的空目录"
    else
        success "已删除 $deleted_dirs 个空目录:"
        for tmp in ${empty_dirs[@]};do
			echo "$tmp"
		done
    fi
}

function cmake_uninstall()
{
	cdi ${PROJECT_ROOT}
    prt "${PINK}cur_path :$(pwd)${CLS}"
	cmake_check || { 
		return 1 
	}
    # 创建构建目录
	if [ ! -d "build" ];then
		warning "build 目录不存在!"
		return 0
	fi 

	cdi build
	info "将卸载 ${CMAKE_INSTALL_PATH} 中本工程安装的文件..."
	${CMAKE} --build . --target uninstall
	cdo

	if [ -d "${CMAKE_INSTALL_PATH}" ] && command -v tree &> /dev/null; then
		cdi ${CMAKE_INSTALL_PATH}
		tree . -L 5
		cdo
	fi
	
	success "成果物卸载完毕!"
	# cmake_rm_empty_dirs ${CMAKE_INSTALL_PATH} # cmake_uninstall.cmake.in 支持生成的目标直接删除空目录的话可以注释掉这里
	cdo
}

function clangd_clean_cache_dirs() 
{
	cdi ${PROJECT_ROOT}
	prt "${PINK}cur_path :$(pwd)${CLS}"
    info "开始清理.cache目录和compile_commands.json文件..."
	# 删除所有.cache目录
	# find . -type d -name ".cache" 从当前目录递归查找所有名为 .cache 的目录。
	# -print 显示被删除的目录路径（便于用户确认）。
	# -exec rm -rf {} + 高效删除所有匹配的目录（-rf 强制递归删除）。
	find . -type d -name ".cache" -print -exec rm -rf {} +
	# 删除所有compile_commands.json文件
	# find . -type f -name "compile_commands.json" -print -exec rm -f {} +
	find . -name "compile_commands.json" \( -type f -o -type l \) -print -exec rm -f {} +
	success "clangd相关文件和目录清理完成!"
	cdo
}

function build_all()
{
    cmake_build_all
}

function clean_all()
{
    cmake_clean_all
	clangd_clean_cache_dirs
}

# 自动执行所有步骤
function auto_setup() 
{
	if [ "$BUILD_MODE" = "build" ]; then
    	build_all
	elif [ "$BUILD_MODE" = "clean" ]; then
		clean_all
	elif [ "$BUILD_MODE" = "install" ]; then
		cmake_install
	elif [ "$BUILD_MODE" = "uninstall" ]; then
		cmake_uninstall
	else
		warning "No executable steps..."
	fi
    success "所有步骤执行完成!"
}

# 菜单与主进程
# ========================================================
function show_menu()
{
    message "================================================="
	message "                script by @苏木    ${CLS}"
	message "================================================="
    prt "${PINK}current path         :$(pwd)${CLS}"
    prt "${PINK}PROJECT_ROOT         :${PROJECT_ROOT}${CLS}"
    echo ""
    prt "* [0] cmake 工程编译"
	prt "* [1] cmake 成果物安装"
    prt "* [2] cmake 工程清理"
    prt "* [3] cmake 成果物卸载"
	prt "* [4] 清理clangd相关文件"
    prt "* [9] 退出"
    echo "================================================="
}

# 主逻辑
function main() 
{
    if [ "$EXECUTE_MODE" = "manu" ]; then
        while true; do
            show_menu
            read -p "请选择操作 (0-5): " choice
            case "${choice}" in
				"0") cmake_build_all;;
				"1") cmake_install;;
				"2") cmake_clean_all;;
				"3") cmake_uninstall;;
				"4") clangd_clean_cache_dirs;;
                "9") exit 0;;
                *) error "无效选项!!!" ;;
            esac
            read -p "按回车继续..."
        done
    else
        info "正在自动执行所有配置步骤..."
        auto_setup
    fi
}

# 执行入口
# show_menu # 菜单显示
main "$@" # 主逻辑执行
